package org.jeecg.modules.third.openapi;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.LngLonUtil;
import org.jeecg.modules.third.openapi.dto.ParkInfo;
import org.jeecg.modules.third.openapi.dto.WaybillRoute;
import org.jeecg.modules.wlhy.hyconfig.entity.HyConfig;
import org.jeecg.modules.wlhy.hyevent.event.HistoryTraceEvent;
import org.jeecg.modules.wlhy.hyhistorytrace.entity.HyHistoryTrace;
import org.jeecg.modules.wlhy.hyhistorytrace.service.IHyHistoryTraceService;
import org.jeecg.modules.wlhy.hyvehicle.entity.HyVehicle;
import org.jeecg.modules.wlhy.hyvehicle.service.IHyVehicleService;
import org.jeecg.modules.wlhy.hyzyb.dto.DeviceTrackDTO;
import org.jeecg.modules.wlhy.hyzyb.service.IHyZybService;
import org.jeecg.modules.wlhy.shipping.entity.PointDataListVO;
import org.jeecg.modules.wlhy.shipping.entity.WaybillRouteVO;
import org.jeecg.modules.wlhy.utils.HyConfigUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description: TODO
 * @author: duanlikao
 * @date: 2022年10月07日 12:29
 */
@Service
@Slf4j
public class WaybillRouteService {

    @Autowired
    private OpenApiService openApiService;

    @Autowired
    private IHyVehicleService vehicleService;

    @Autowired
    private IHyZybService zybService;

    @Autowired
    private ZJHYWaybillRouteService zjhyWaybillRouteService;

    @Autowired
    private IHyHistoryTraceService hyHistoryTraceService;

    @Autowired
    private ZWLWaybillRouteService zwlWaybillRouteService;

   @Autowired
   private XDWaybillRouteService xdWaybillRouteService;

    /**
     * 获取运单历史轨迹，（文件中存储的轨迹）
     */
    public WaybillRouteVO getWaybillByFile(String shippingNoteNumber) {

        HyHistoryTrace trace = this.hyHistoryTraceService.getOne(new LambdaQueryWrapper<HyHistoryTrace>()
                .eq(HyHistoryTrace::getShippingNoteNumber, shippingNoteNumber));

        log.info("加载历史轨迹数据, {}", JSONUtil.toJsonStr(trace));
        if (null == trace || StrUtil.isEmpty(trace.getTraceFilepath())) {
            return null;
        }

        try {
            String content = FileUtil.readUtf8String(trace.getTraceFilepath());
            HistoryTraceEvent historyTraceEvent = JSONUtil.toBean(content, HistoryTraceEvent.class);
            return historyTraceEvent.getWaybillRouteVO();
        } catch (Exception e) {
            e.printStackTrace();
        }

        log.error("历史轨迹文件不存在 {}", shippingNoteNumber);
        return null;
    }


    /**
     * 获取运单的车辆轨迹 组装转换数据
     *
     * @param vehicleNo
     * @param startTime
     * @param endTime
     * @return
     */
    public WaybillRouteVO getWaybillRoute(String vehicleNo, String vehicleColorCode, String startTime, String endTime, String toType) {

        //中交轨迹和交通部字典值不一样，黄绿车牌交通部要求93，中交是3
        if ("93".equals(vehicleColorCode)) {
            vehicleColorCode = "3";
        }

        //中交慧联的轨迹，如果开启这个开关走慧联轨迹
        HyConfig systemConfig = HyConfigUtils.getConfig();
        if (systemConfig != null && systemConfig.getXzApiIzUse()) {
            log.info("获取中交慧联轨迹,参数{} {} {} {}", vehicleNo, vehicleColorCode, startTime, endTime );
            return this.zjhyWaybillRouteService.getWaybillRoute(vehicleNo, vehicleColorCode, startTime, endTime, toType);
        }

        log.info("获取中交轨迹,参数{} {} {} {}", vehicleNo, vehicleColorCode, startTime, endTime );
        //HyVehicle hyVehicle = vehicleService.getHyVehicleByVehicleNumber(vehicleNo);
        //String vco = hyVehicle != null && StringUtils.isNotEmpty(hyVehicle.getVehiclePlateColorCode()) ? hyVehicle.getVehiclePlateColorCode() : "2";

        Date statusDtLoading = DateUtils.stringToDateTime(startTime);
        Date statusDtUnloading = DateUtils.stringToDateTime(endTime);
        int second = DateUtils.getDifferentDaysByMillisecond(statusDtLoading, statusDtUnloading);
        List<WaybillRoute> waybillRoutes = new ArrayList<>();
        WaybillRouteVO waybillRouteVO = new WaybillRouteVO();

        try {
            int days = 1;
            if (second > 86400*2) {
                BigDecimal diff = new BigDecimal(second*1000).divide(new BigDecimal(86400000*2),7, BigDecimal.ROUND_HALF_UP);
                days = (int) Math.ceil(diff.doubleValue());
            }

            if (days == 1) {
                String res = openApiService.routerPath(vehicleNo, vehicleColorCode, startTime, endTime,"0");
                if (StringUtils.isNotEmpty(res)) {
                    JSONObject jsonObject = JSONObject.parseObject(res);
                    JSONObject jsonObjectResult = jsonObject.getJSONObject("result");
                    if (jsonObjectResult != null) {
                        String trackArray = jsonObjectResult.getString("trackArray");
                        waybillRoutes = JSONObject.parseArray(trackArray, WaybillRoute.class);
                        waybillRouteVO.setMileage(jsonObjectResult.getString("mileage"));
                    }
                }
            } else {
                double mileageDouble = 0;
                Set<String> errorMessages = new HashSet<>();
                for (int i = 1; i <= days; i++) {
                    Calendar calendar = new GregorianCalendar();
                    calendar.setTime(statusDtLoading);
                    calendar.add(Calendar.DATE, 2);// 把日期往后增加一天.整数往后推,负数往前移动
                    Date endDate = calendar.getTime(); // 这个时间就是日期往后推一天的结果
                    String newEndTime = i == days ? DateUtils.dateTimeToString(statusDtUnloading) : DateUtils.dateTimeToString(endDate);
                    String newStartTime = DateUtils.dateTimeToString(statusDtLoading);
                    String res = null;
                    try {
                        res = openApiService.routerPath(vehicleNo, vehicleColorCode, newStartTime, newEndTime,"0");
                    } catch (Exception ex) {
                        log.info("WaybillRouteService  getWaybillRoute  vehicleNo|{}, vco|{}, startTime|{}, endTime |{} ,Exception |{}"
                                ,vehicleNo, vehicleColorCode, newStartTime, newEndTime,ex.getMessage());
                        errorMessages.add( ex.getMessage() );
                    }

                    if (StringUtils.isNotEmpty(res)) {
                        JSONObject jsonObject = JSONObject.parseObject(res);
                        JSONObject jsonObjectResult = jsonObject.getJSONObject("result");
                        if (jsonObjectResult != null) {
                            String trackArray = jsonObjectResult.getString("trackArray");
                            List<WaybillRoute> newWaybillRoutes = JSONObject.parseArray(trackArray, WaybillRoute.class);
                            waybillRoutes.addAll(newWaybillRoutes);

                            String mileageString = jsonObjectResult.getString("mileage");
                            if(StringUtils.isNotBlank(mileageString)){
                                mileageDouble = mileageDouble +  Double.valueOf(mileageString);
                            }
                        }

                    }
                    statusDtLoading = endDate;
                }
                waybillRouteVO.setMileage(String.valueOf(mileageDouble));
                if (CollectionUtils.isEmpty(waybillRoutes) && errorMessages.size() > 0  ) {
                    throw new JeecgBootException( StringUtils.join(errorMessages,","));
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("WaybillRouteService  getWaybillRoute  Exception |{}", e.getMessage());
            throw new JeecgBootException(e.getMessage());
        }

        if (CollectionUtils.isNotEmpty(waybillRoutes)) {
            List<PointDataListVO> pointDataListVOs = new ArrayList();
            List<List<String>> valueList = new ArrayList<>();
            for (WaybillRoute waybillRoute : waybillRoutes) {
                //Double.parseDouble(waybillRoute.getSpd())
                Double spd = Double.valueOf(waybillRoute.getSpd());
                if (spd > 0) {
                    PointDataListVO pointDataListVO = new PointDataListVO();
                    Double lat = Double.valueOf(waybillRoute.getLat()) / 600000;
                    Double lan = Double.valueOf(waybillRoute.getLon()) / 600000;
                    double[] gcj02;
                    if (StringUtils.isNotEmpty(toType) && toType.equals("GCJ02")) {
                        gcj02 = LngLonUtil.gps84_To_Gcj02(lat, lan);
                    } else {
                        gcj02 = LngLonUtil.gps84_To_bd09(lat, lan);
                    }
                    pointDataListVO.setCs(spd);
                    pointDataListVO.setLat(String.valueOf(gcj02[0]));
                    pointDataListVO.setLng(String.valueOf(gcj02[1]));

                    String gtm = waybillRoute.getGtm().replace("/", "");
                    String strGtm = DateUtils.strDateTimeToFormatString(gtm);
                    pointDataListVO.setReceiveTime(strGtm);
                    pointDataListVOs.add(pointDataListVO);

                    List<String> valueListString = new ArrayList<>();
                    valueListString.add(String.valueOf(gcj02[1]));
                    valueListString.add(String.valueOf(gcj02[0]));
                    valueList.add(valueListString);
                }

            }
            waybillRouteVO.setLineArray(valueList);
            waybillRouteVO.setPointDataList(pointDataListVOs);
        }
        return waybillRouteVO;
    }




    /**
     * 获取车辆轨迹
     * @param vehicleNo
     * @param startTime
     * @param endTime
     * @param parkMins
     * @return
     */
    public WaybillRouteVO getRouterPath(String vehicleNo, String startTime,String endTime ,String parkMins){

        //中交慧联的轨迹，如果开启这个开关走慧联轨迹
        HyConfig systemConfig = HyConfigUtils.getConfig();
        if (systemConfig != null && systemConfig.getXzApiIzUse()) {
            log.info("获取中交慧联轨迹,参数{} {} {} {}", vehicleNo, startTime, endTime );
            return this.zjhyWaybillRouteService.getRouterPath(vehicleNo, startTime, endTime, parkMins);
        }else if (systemConfig != null && systemConfig.getZwlIsUse()!=null&&systemConfig.getZwlIsUse()){
            log.info("获取中物联轨迹,参数{} {} {} {}", vehicleNo, startTime, endTime );
            return this.zwlWaybillRouteService.getHistoryShippingTrack(vehicleNo, startTime, endTime, parkMins);
        }else if (systemConfig.getXdIsUse()!=null&&systemConfig!=null&&systemConfig.getXdIsUse()){
            log.info("获取信达轨迹,参数{} {} {} {}", vehicleNo, startTime, endTime );
            return xdWaybillRouteService.getShippingTrack(vehicleNo,startTime,endTime);
        }

        log.info("获取中交轨迹,参数{} {} {} {}", vehicleNo, startTime, endTime , parkMins);
        HyVehicle hyVehicle = vehicleService.getHyVehicleByVehicleNumber(vehicleNo);

        String vco = hyVehicle != null && StringUtils.isNotEmpty(hyVehicle.getVehiclePlateColorCode()) ? hyVehicle.getVehiclePlateColorCode() : "2";
        //中交轨迹和交通部字典值不一样，黄绿车牌交通部要求93，中交是3
        if ("93".equals(vco)) {
            vco = "3";
        }

        Date statusDtLoading = DateUtils.stringToDateTime(startTime);
        Date statusDtUnloading = DateUtils.stringToDateTime(endTime);
        if(statusDtLoading==null){
            statusDtLoading = DateUtil.parse(startTime);
            startTime=  statusDtLoading.toString();
//            startTime= DateUtil.formatDate(statusDtLoading);
        }
        if(statusDtUnloading==null){
            statusDtUnloading = DateUtil.parse(endTime);
            endTime=  statusDtUnloading.toString();
//            endTime= DateUtil.formatDate(statusDtUnloading);
        }
        int second = DateUtils.getDifferentDaysByMillisecond(statusDtLoading, statusDtUnloading);
        List<WaybillRoute> waybillRoutes = new ArrayList<>();
        List<ParkInfo> parkInfos = new ArrayList<>();
        WaybillRouteVO waybillRouteVO = new WaybillRouteVO();
        try {
            int days = 1;
            if (second > 86400*2) {
                BigDecimal diff = new BigDecimal(second*1000).divide(new BigDecimal(86400000*2),7, BigDecimal.ROUND_HALF_UP);
                days = (int) Math.ceil(diff.doubleValue());
            }

            if (days == 1) {
                String res = openApiService.routerPath(vehicleNo, vco, startTime, endTime,parkMins);
                if (StringUtils.isNotEmpty(res)) {
                    JSONObject jsonObject = JSONObject.parseObject(res);
                    JSONObject jsonObjectResult = jsonObject.getJSONObject("result");
                    if (jsonObjectResult != null) {
                        //路程总里程
                        String mileage = jsonObjectResult.getString("mileage");
                        //停车次数
                        //int parkSize = jsonObjectResult.getIntValue("parkSize");
                        String trackArray = jsonObjectResult.getString("trackArray");
                        if(StringUtils.isNotBlank(trackArray)) {
                            waybillRoutes = JSONObject.parseArray(trackArray, WaybillRoute.class);
                        }

                        String parkArray = jsonObjectResult.getString("parkArray");
                        if(StringUtils.isNotBlank(parkArray)){
                            parkInfos = JSONObject.parseArray(parkArray, ParkInfo.class);
                        }

                        waybillRouteVO.setMileage(mileage);

                    }
                }
            } else {
                double mileageDouble = 0;
                Set<String> errorMessages = new HashSet<>();
                for (int i = 1; i <= days; i++) {
                    Calendar calendar = new GregorianCalendar();
                    calendar.setTime(statusDtLoading);
                    //把日期往后增加三天.整数往后推,负数往前移动
                    calendar.add(Calendar.DATE, 2);
                    //这个时间就是日期往后推一天的结果
                    Date endDate = calendar.getTime();
                    String newEndTime = i == days ? DateUtils.dateTimeToString(statusDtUnloading) : DateUtils.dateTimeToString(endDate);
                    String newStartTime = DateUtils.dateTimeToString(statusDtLoading);
                    String res = null;
                    try {
                        res =  openApiService.routerPath(vehicleNo, vco, newStartTime, newEndTime,parkMins);
                    } catch (Exception ex) {
                        log.info("WaybillRouteService  getRouterPath  vehicleNo|{}, vco|{}, startTime|{}, endTime |{} ,Exception |{}"
                                ,vehicleNo, vco, newStartTime, newEndTime,ex.getMessage());

                        errorMessages.add( ex.getMessage() );

                    }
                    if (StringUtils.isNotEmpty(res)) {
                        JSONObject jsonObject = JSONObject.parseObject(res);
                        JSONObject jsonObjectResult = jsonObject.getJSONObject("result");
                        if (jsonObjectResult != null) {
                            String trackArray = jsonObjectResult.getString("trackArray");
                            if(StringUtils.isNotBlank(trackArray)) {
                                waybillRoutes.addAll(JSONObject.parseArray(trackArray, WaybillRoute.class));
                            }

                            String parkArray = jsonObjectResult.getString("parkArray");
                            if(StringUtils.isNotBlank(parkArray)){
                                parkInfos.addAll(JSONObject.parseArray(parkArray, ParkInfo.class));
                            }
                            String mileageString = jsonObjectResult.getString("mileage");
                            if(StringUtils.isNotBlank(mileageString)){
                                mileageDouble = mileageDouble +  Double.valueOf(mileageString);
                            }
                        }

                    }
                    statusDtLoading = endDate;
                }
                waybillRouteVO.setMileage(String.valueOf(mileageDouble));
                if (CollectionUtils.isEmpty(waybillRoutes) && errorMessages.size() > 0  ) {
                    throw new JeecgBootException( StringUtils.join(errorMessages,","));
                }
            }
        } catch (Exception e) {
            log.info("WaybillRouteService  getRouterPath  Exception |{}", e.getMessage());
            throw new JeecgBootException(e.getMessage());
        }
        Map<String,ParkInfo > parkInfoMaps = new HashMap<>();
        if (CollectionUtils.isNotEmpty(parkInfos)) {
            for(ParkInfo parkInfo : parkInfos){
                parkInfoMaps.put(parkInfo.getParkLon()+"_"+parkInfo.getParkLat(),parkInfo);
            }
        }

        if (CollectionUtils.isNotEmpty(waybillRoutes)) {

            List<PointDataListVO> pointDataListVOs = new ArrayList();
            List<List<String>> valueList = new ArrayList<>();
            List<ParkInfo> parkInfoList =  new ArrayList<>();
            for (WaybillRoute waybillRoute : waybillRoutes) {

                PointDataListVO pointDataListVO = new PointDataListVO();
                //Double.parseDouble(waybillRoute.getSpd())
                Double spd = Double.valueOf(waybillRoute.getSpd());
                pointDataListVO.setCs(spd);

                double lat = Double.valueOf(waybillRoute.getLat()) / 600000;
                double lan = Double.valueOf(waybillRoute.getLon()) / 600000;
                double[]  gcj02 = LngLonUtil.gps84_To_Gcj02(lat, lan);

                pointDataListVO.setLat(String.valueOf(gcj02[0]));
                pointDataListVO.setLng(String.valueOf(gcj02[1]));

                String gtm = waybillRoute.getGtm().replace("/", "");
                String strGtm = DateUtils.strDateTimeToFormatString(gtm);
                pointDataListVO.setReceiveTime(strGtm);
                //停车信息
                if(parkInfoMaps.size() > 0){
                    String key = waybillRoute.getLon()+"_"+waybillRoute.getLat();
                   if(parkInfoMaps.get(key) != null){

                       for(ParkInfo parkInfo : parkInfos){

                           String key1 = parkInfo.getParkLon()+"_"+parkInfo.getParkLat();
                           if(key1.equals(key)){
                               String parkBte  =  StringUtils.isNotBlank(parkInfo.getParkBte()) ?  DateUtils.timestamptoStr2( Long.valueOf(parkInfo.getParkBte() )) : "";
                               String parkEte  =  StringUtils.isNotBlank(parkInfo.getParkEte()) ?  DateUtils.timestamptoStr2( Long.valueOf(parkInfo.getParkEte() )) : "";

                               parkInfo.setParkBte( parkBte );
                               parkInfo.setParkEte( parkEte );
                               parkInfo.setParkLon(String.valueOf(gcj02[1]));
                               parkInfo.setParkLat(String.valueOf(gcj02[0]));
                               parkInfoList.add(parkInfo);

                               pointDataListVO.setParkAdr(parkInfo.getParkAdr());
                               pointDataListVO.setParkBte( parkBte );
                               pointDataListVO.setParkEte( parkEte );
                               pointDataListVO.setParkLon(String.valueOf(gcj02[1]));
                               pointDataListVO.setParkLat(String.valueOf(gcj02[0]));
                               pointDataListVO.setParkMins(parkInfo.getParkMins());
                           }
                       }
                   }
                }

                pointDataListVOs.add(pointDataListVO);

                List<String> valueListString = new ArrayList<>();
                valueListString.add(String.valueOf(gcj02[1]));
                valueListString.add(String.valueOf(gcj02[0]));
                valueList.add(valueListString);
            }

            waybillRouteVO.setParkInfoList(parkInfoList);
            waybillRouteVO.setLineArray(valueList);
            waybillRouteVO.setPointDataList(pointDataListVOs);
        }

        return waybillRouteVO;
    }


    /**
     * 实时轨迹
     * @param vehicleNo
     * @return
     */
    public String getRealLocation(String vehicleNo) {
        HyVehicle hyVehicle = vehicleService.getHyVehicleByVehicleNumber(vehicleNo);
        String vehiclePlateColorCode =  hyVehicle != null && StringUtils.isNotBlank(hyVehicle.getVehiclePlateColorCode() ) ?
                hyVehicle.getVehiclePlateColorCode() : "2";
        if ("93".equals(vehiclePlateColorCode)) {
            vehiclePlateColorCode = "3";
        }

        String res = openApiService.transTimeManage(vehicleNo, vehiclePlateColorCode);
        if(StringUtils.isBlank(res)){
            throw new JeecgBootException("获取数据异常,请稍后重试。");
        }
        JSONObject jsonObject = JSONObject.parseObject(res);
        Map<String, Object> map = new HashMap< >();
        if(1001 == jsonObject.getIntValue("status")){
            JSONObject  resultJSONObject =  jsonObject.getJSONObject("result");
            if(resultJSONObject != null){
                JSONObject firstVcl =  resultJSONObject.getJSONObject("firstVcl") ;
                if(firstVcl != null ){
                    map.put("status","1001");
                    map.put("result" ,firstVcl);
                    return JSONObject.toJSONString(map);
                }
            }
        }

        map.put("status","1006");
        return JSONObject.toJSONString(map);
    }


    //获取智运宝设备轨迹
    //"result": [
    //		{
    //			"device": "868120261074147",
    //			"locateTime": 1683373705,
    //			"locateType": 1,
    //			"locateTypeName": "GPS定位",
    //			"lng": 114.546683,
    //			"lat": 36.902202,
    //			"address": null,
    //			"direction": 305,
    //			"directionName": "西北 (305°)",
    //			"speed": 29
    //		},....]
    public WaybillRouteVO getZybShippingTrack(String zybShippingNoteNumber) {

        log.info("开始获取智运宝运单{}智运宝轨迹", zybShippingNoteNumber);
        Result result = this.zybService.getShippingTrack(zybShippingNoteNumber);
        if (CommonConstant.SC_OK_200.equals(result.getCode())) {
            log.error("后台运单列表获取智运宝轨迹失败，{}", result.getMessage());
            return null;
        }

        //拼装数据
        WaybillRouteVO waybillRouteVO = new WaybillRouteVO();
        List<PointDataListVO> pointDataListVOList = new ArrayList<>();
        List<List<String>> lineValueList = new ArrayList<>();
        SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );

        List<DeviceTrackDTO> deviceTrackDTOList = JSONUtil.parseArray(JSONUtil.toJsonStr(result.getResult())).toList(DeviceTrackDTO.class);
        for (DeviceTrackDTO zybTrack : deviceTrackDTOList) {
            PointDataListVO pointDataVO = new PointDataListVO();

            String datetime = format.format(new Date(zybTrack.getLocateTime().longValue() * 1000));
            pointDataVO.setReceiveTime(datetime);
            if (null != zybTrack.getSpeed()) {
                pointDataVO.setCs(zybTrack.getSpeed().doubleValue());
            } else {
                pointDataVO.setCs(0.00);
            }
            pointDataVO.setLng(String.valueOf(zybTrack.getLng()));
            pointDataVO.setLat(String.valueOf(zybTrack.getLat()));
            pointDataListVOList.add(pointDataVO);

            List<String> valueList = new ArrayList<>();
            valueList.add(String.valueOf(zybTrack.getLng()));
            valueList.add(String.valueOf(zybTrack.getLat()));
            lineValueList.add(valueList);
        }

        waybillRouteVO.setLineArray(lineValueList);
        waybillRouteVO.setPointDataList(pointDataListVOList);

        return waybillRouteVO;
    }

}
